/*->c.DrawLib */

/* Library of functions to make Draw files */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "h.os"
#include "h.bbc"
#include "h.wimp"
#include "h.wimpt"
#include "h.flex"

#include "h.drawlevel0"


#include "h.def"
#include "h.wos"

#include "h.ram"
#include "h.xext"


#include "h.tekint"


/*****************************************************************************/

char fontname[48]="\1Tek.Medium";
int  fwidth=600;


void settekfont(int fp)
{
 strcpy(fontname+1,stringptr(stack[fp]));
 if(stack[fp+1]>0) fwidth=stack[fp+1];
}


/*****************************************************************************/


#define DRAW   0xAFF

#define WIDTH 0


#define DCHUNK 0x1000


static int cpx;       /* x font size in Draw units */
static int cpfx;      /* font painter cpx */
static int cpy;       /* y font size in Draw units */
static int cx=0;
static int cy=0;
static int drawtoff; /* flags the start of the line object */
static int drawfoff; /* flags the start of the text object */
static int textlen;
static int xlo,xhi,ylo,yhi;
static int abended;
static int clinestyle;
static int linecolour;
static int fontfcolour;
static int fontbcolour;

int drawheadersize;

/*****************************************************************************/

void flushdraw(Draw_diag * diag)
{
 int * drawt;

 if(drawtoff)
 {
  drawt=(int*)(diag->data+drawtoff);

/*  dprintf(6,"flush len=%d",(diag->length-drawtoff+4));  */

  *drawt++=(diag->length-drawtoff+4);
  *drawt++=xlo;
  *drawt++=ylo;
  *drawt++=xhi;
  *drawt++=yhi;
 }
}


void closedraw(Draw_diag * diag)
{
 flushdraw(diag);
 drawtoff=0;
}



static int styletab[8][5]=
{
 2,  512,  512,    0,    0,            /* style ` */
 2, 2048, 2048,    0,    0,            /* style a */
 2,  512,  512,    0,    0,            /* style b */
 2,  512,  512,    0,    0,            /* style c */
 2,  512,  512,    0,    0,            /* style d */
 2,  512,  512,    0,    0,            /* style e */
 2,  512,  512,    0,    0,            /* style f */
 2,  512,  512,    0,    0             /* style g */
};



void startdraw(int x,int y,Draw_diag * diag)
{
 int * buffp;
 int   nelem;
 int   i;

 if(!drawtoff)
 {
  flex_chunk((flex_ptr)&(diag->data),diag->length+68,DCHUNK);

  buffp=(int*)(diag->data+diag->length);

  xlo=x-2*WIDTH;
  xhi=x+2*WIDTH;
  ylo=y-2*WIDTH;
  yhi=y+2*WIDTH;

  *buffp++=2;
  diag->length+=4;

  drawtoff=diag->length;
  *buffp++=17*4;

  *buffp++=xlo;
  *buffp++=ylo;
  *buffp++=xhi;
  *buffp++=yhi;

  *buffp++=-1;             /* fill colour */
  *buffp++=linecolour;     /* outline colour */
  *buffp++=WIDTH;          /* width */

  if(clinestyle)           /* dash pattern defn. */
  {
   *buffp++=(1<<7);
   *buffp++=0;             /* distance into pattern to start */
   *buffp++=nelem=styletab[clinestyle][0];
   for(i=0;i<nelem;i++) *buffp++=styletab[clinestyle][i+1];
   diag->length+=(nelem+2)*4;
  }
  else
  {
   *buffp++=0;              /* style */
  }                          

  diag->length+=9*4;

  *buffp++=0;
  diag->length+=4;

 }
 else
 {
  if(x<xlo) {xlo=x-2*WIDTH;}
  if(x>xhi) {xhi=x+2*WIDTH;}
  if(y<ylo) {ylo=y-2*WIDTH;}
  if(y>yhi) {yhi=y+2*WIDTH;}
 }
}



void vecmove(int x, int y,Draw_diag * diag)
{
 int * buffp;

 if(abended) return;

 if(cx==x && cy==y && drawtoff) return;

 flex_chunk((flex_ptr)&(diag->data),diag->length+12,DCHUNK);

 cx=x;
 cy=y;

 closefont(diag);
 startdraw(x,y,diag);
 buffp=(int*)(diag->data+diag->length-4);
 *buffp++=2; /* tag == move */
 *buffp++=x;
 *buffp++=y;
 diag->length+=8;

 *buffp++=0;
 diag->length+=4;
}



void vecdraw(int x,int y,Draw_diag * diag)
{
 int * buffp;

 if(abended) return;

 flex_chunk((flex_ptr)&(diag->data),diag->length+12,DCHUNK);

 cx=x;
 cy=y;

 closefont(diag);
 startdraw(x,y,diag);
 buffp=(int*)(diag->data+diag->length-4);
 *buffp++=8; /* tag == draw */
 *buffp++=x;
 *buffp++=y;
 diag->length+=8;

 *buffp++=0;
 diag->length+=4;
}



void veclinecolour(int pal,Draw_diag * diag)
{
 if(pal!=linecolour)
 {
  closedraw(diag);
  linecolour=pal;
 } 
}



void veccurve(int x1,int y1,int x2,int y2,int x3,int y3,Draw_diag * diag)
{
 int * buffp;

 if(abended) return;

 flex_chunk((flex_ptr)&(diag->data),diag->length+28,DCHUNK);

 cx=x3;
 cy=y3;

 closefont(diag);
 startdraw(x1,y1,diag);
 buffp=(int*)(diag->data+diag->length-4);

 *buffp++=6; /* tag == curve */
 *buffp++=x1;
 *buffp++=y1;
 *buffp++=x2;
 *buffp++=y2;
 *buffp++=x3;
 *buffp++=y3;

 diag->length+=24;

 *buffp++=0;
 diag->length+=4;

}



void veclinestyle(int style,Draw_diag * diag)
{
 if(style!=clinestyle)
 {
  closedraw(diag);
  clinestyle=style;
 }
}



void vectextsize(int xsize,int ysize,Draw_diag * diag)
{
 if(cpx!=xsize || cpy!=ysize)
 {
  closefont(diag);
  cpx=xsize;
  cpfx=(cpx*1000)/fwidth;
  cpy=ysize;
 }
}




void vectextcolour(int fpal,int bpal,Draw_diag * diag)
{
 if(fontfcolour!=fpal || fontbcolour!=bpal)
 {
  closefont(diag);
  fontfcolour=fpal;
  fontbcolour=bpal;
 }
}





void flushfont(Draw_diag * diag)
{
 int * drawt;

 if(drawfoff)
 {
  drawt=(int*)(diag->data+drawfoff);
  *drawt++=(diag->length-drawfoff+4);
  *drawt++=xlo;
  *drawt++=ylo;
  *drawt++=xhi;
  *drawt++=yhi;
 }
}



void closefont(Draw_diag * diag)
{
 flushfont(diag);
 drawfoff=0;
}




void startfont(int x,int y,Draw_diag * diag)
{
 int * buffp;

 if(!drawfoff)
 {
  flex_chunk((flex_ptr)&(diag->data),diag->length+56,DCHUNK);

  buffp=(int*)(diag->data+diag->length);

  *buffp++=1;
  diag->length+=4;
  drawfoff=diag->length;
  *buffp++=16*4;

  *buffp++=xlo;
  *buffp++=ylo;
  *buffp++=xhi;
  *buffp++=yhi;

  *buffp++=fontfcolour; /* colour */
  *buffp++=fontbcolour; /* background */
  *buffp++=1;           /* font */
  *buffp++=cpfx;        /* x font size */
  *buffp++=cpy;         /* y font size */

  *buffp++=x;
  *buffp++=y;

  *buffp++=0;           /* zero len string */

  xhi=xlo=x;
  ylo=y-cpy;
  yhi=y+cpy;

  textlen=0;

  diag->length+=13*4;
 }
}




void vecsym(int x,int y,int c,Draw_diag * diag)
{
 int * buffp;

 closedraw(diag);
 if(drawfoff && (x!=xhi || y!=(ylo+cpy))) closefont(diag);
 startfont(x,y,diag);

 buffp=(int*)(diag->data+diag->length);

 *(((char*)buffp)-4+(textlen & 0x3))=c;
 xhi+=cpx;
 textlen++;
 if(!(textlen & 0x3))
 {
  flex_chunk((flex_ptr)&(diag->data),diag->length+4,DCHUNK);
  *buffp++=0;
  diag->length+=4;
 }
}









void invertsub(int * word)
{
 int   col;
 int   r;
 int   g;
 int   b;

 col=*word;
 if(col==-1) return;

 r=(col>>8)  & 0xFF;
 g=(col>>16) & 0xFF;
 b=(col>>24) & 0xFF;

/*
 if(r==g && g==b)
 {
  r=255-r;
  col=(r<<24)+(r<<16)+(r<<8);
  *word=col;
 }
 */

 r=255-r;
 b=255-b;
 g=255-g;

 col=(b<<24)+(g<<16)+(r<<8);
 *word=col;
}


/* swops black/white in diagram */

void invertdiag(Draw_diag * diag)
{
 int * buffp=(int*)(diag->data+40);
 int * buffm=(int*)(diag->data+diag->length);

 buffm-=6;

 while(buffp<buffm)
 {
  switch(*buffp)
  {
   case 1:              /* font */
          invertsub(buffp+6);
          invertsub(buffp+7);
          break;

   case 2:              /* line */
          invertsub(buffp+6);
          invertsub(buffp+7);
          break;

  }

  buffp=buffp+((*(buffp+1))/sizeof(int));
 }
}




void vecfillcolour(int fillcolour,Draw_diag * diag,int offset)
{
 int * buffp;

 if(!diag->data || diag->length<=offset)
 {
 /* dprintf(0,"fill failed data=%x length=%d offset=%d",diag->data,
                                   diag->length,offset); */
  return;
 }

 buffp=(int*)(diag->data+offset);

/* dprintf(0,"*buff=%d fill=%d offset=%d",*buffp,fillcolour,offset); */

 if(*buffp==2) *(buffp+6)=fillcolour;
 else
 {
 /* dprintf(0,"miss *buff=%d fill=%d offset=%d",*buffp,fillcolour); */
 }
}






int itemsdiag(Draw_diag * diag)
{
 int * buffp=(int*)(diag->data+40);
 int * buffm=(int*)(diag->data+diag->length);
 int   items=0;

 while(buffp<buffm)
 {
  items++;
  buffp=buffp+((*(buffp+1))/sizeof(int));
 }

 return(items);
}



/* reduces dsub to just two elements */

void compactdiag(Draw_diag * dsub,Draw_diag * dmain)
{
 int * buffp=(int*)(dsub->data+drawheadersize);
 int * buffs=buffp;
 int * buffl=buffp;
 int * buffm=(int*)(dsub->data+dsub->length);
 int   items=0;

 int   extra;


 while(buffp<buffm)
 {
  items++;
  buffl=buffp;
  buffp=buffp+((*(buffp+1))/sizeof(int));
 }

 if(items>1)     /* remove stuff from buffs upto buffl */
 {
  extra=(buffl-buffs)*sizeof(int);
    
/*  dprintf(1,"extra=%d items=%d",extra,items); */

                                                 /*  copy data to main */


  flex_chunk((flex_ptr)&(dmain->data),dmain->length+extra,DCHUNK);
  memcpy(dmain->data+dmain->length,dsub->data+drawheadersize,extra);
  dmain->length+=extra;

                                                 /* remove from sub */

  memmove(dsub->data+drawheadersize,dsub->data+drawheadersize+extra,
                                                         dsub->length-extra);
  dsub->length-=extra;
  flex_chunk((flex_ptr)&(dsub->data),dsub->length,DCHUNK);

  if(drawtoff) drawtoff-=extra;
  if(drawfoff) drawfoff-=extra;

/* dprintf(2,"tekpan=%d extra=%d drawfoff=%d",tekpaneloffset,extra,drawfoff); */



 }
}



void mergediag(Draw_diag * dsub,Draw_diag * dmain)
{
 int extra=dsub->length-drawheadersize;

 flex_chunk((flex_ptr)&(dmain->data),dmain->length+extra,DCHUNK);
 memcpy(dmain->data+dmain->length,dsub->data+drawheadersize,extra);
 dmain->length+=extra;
}




void doopen(Draw_diag * diag,int xsize,int ysize)
{
 int * buffp=(int*)diag->data;
 int * buff=buffp;
 int   fnlen;

 strcpy((char*)buffp,"Draw");
 buffp++;
 *buffp++=201;
 *buffp++=0;

 strcpy((char*)buffp,"Hearsay     ");
 buffp+=3;

 *buffp++=0;
 *buffp++=0;
 *buffp++=xsize;
 *buffp++=ysize;

 /* font table object */

 fnlen=strlen(fontname)+1;
 fnlen=(fnlen/sizeof(int))+((fnlen % sizeof(int))!=0);

 *buffp++=0;
 *buffp++=sizeof(int)*(2+fnlen);
 memset((char*)buffp,0,fnlen*sizeof(int));
 strcpy((char*)buffp,fontname);
 buffp+=fnlen;

 drawtoff=0;
 drawfoff=0;
 abended=0;

 drawheadersize=diag->length=(buffp-buff)*sizeof(int);
}


/*****************************************************************************/


/* trash diag contents */

void cleardiag(Draw_diag * diag)
{
 if(diag->data) flex_free((flex_ptr)&(diag->data));
 diag->length=0;
}


/* create a diag */

void opendiag(Draw_diag * diag,int xsize,int ysize)
{
 if(diag->data) flex_chunk((flex_ptr)&(diag->data),0,DCHUNK);
 else           flex_alloc((flex_ptr)&(diag->data),DCHUNK);
 diag->length=0;
 doopen(diag,xsize,ysize);
}



/* makes sure that a diag can be rendered */

void validdiag(Draw_diag * diag)
{
/* dprintf(1,"foff=%d toff=%d",drawfoff,drawtoff);  */

 flushdraw(diag);
 flushfont(diag);
}



/* terminates a diag */

void closediag(Draw_diag * diag)
{
 closedraw(diag);
 closefont(diag);
}



int drawsavediag(char * filename,Draw_diag * diag1,Draw_diag * diag2)
{ 
 FILE * fp;
 int    realfile;

 fp=ropen(filename,"wb");
 if(!fp) return(0);

 if(diag1->data && diag1->length>0)
                   rwrite(diag1->data,1,diag1->length,fp);
 if(diag2->data && diag2->length>drawheadersize) 
                   rwrite(diag2->data+drawheadersize,1,
                          diag2->length-drawheadersize,fp);

 realfile=!ramfp(fp);

 rclose(fp);
 if(realfile) setftype(filename,DRAW);

 return(1);
}




